package com.jctrip.hotel.source.service.greentree.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.jctrip.hotel.common.constant.RedisKeyConstant;
import com.jctrip.hotel.common.constant.XxlJobNameConstant;
import com.jctrip.hotel.common.enums.SourceEnum;
import com.jctrip.hotel.common.threadpool.XxlJobThreadPool;
import com.jctrip.hotel.common.util.DateUtil;
import com.jctrip.hotel.common.util.JsonUtil;
import com.jctrip.hotel.common.util.RedisUtil;
import com.jctrip.hotel.domain.dao.HtHotelStdInfoDao;
import com.jctrip.hotel.domain.entity.*;
import com.jctrip.hotel.source.model.greentree.req.*;
import com.jctrip.hotel.source.model.greentree.resp.*;
import com.jctrip.hotel.source.mq.IncrHotelRocketMqProducer;
import com.jctrip.hotel.source.service.basic.*;
import com.jctrip.hotel.source.service.greentree.GreenTreeService;
import com.jctrip.hotel.source.service.greentree.GreenTreeTaskService;
import com.jctrip.hotel.source.xxl.greentree.thread.*;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.time.DateUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.concurrent.atomic.AtomicReference;
import java.util.stream.Collectors;

/**
 * @Author：Haruhi
 * @description:
 * @Date：2023/9/3 22:26
 * @Package：com.jctrip.hotel.source.service.greentree.impl
 * @Project：hotel-main
 */

@Service
@Slf4j
public class GreenTreeTaskServiceImpl implements GreenTreeTaskService {
    @Resource
    private RedisUtil redisUtil;
    @Resource
    private GreenTreeService greenTreeService;

    @Resource
    private HtHotelStdInfoService htHotelStdInfoService;

    @Resource
    private HtRoomTypeStdInfoService htRoomTypeStdInfoService;

    @Resource
    private HtBreakfastCountGreentreeService htBreakfastCountGreentreeService;

    @Resource
    private HtHotelStdInfoDao htHotelStdInfoDao;

    @Resource
    private HtPriceCalendarService htPriceCalendarService;

    @Resource
    private HtPriceCalendarGreentreeService htGreentreePriceCalendarService;
    @Resource
    private HtHotelStdImageService htHotelStdImageService;
    @Autowired
    private IncrHotelRocketMqProducer incrHotelRocketMqProducer;


    private static final long PUSH_EXPIRY = 1 * 60;

    /**
     * pop任务线程池
     */
    private static final XxlJobThreadPool hotelInfoPopPool =
            new XxlJobThreadPool(XxlJobNameConstant.SYNC_GREENTREE_INFO_POP);

    private static final XxlJobThreadPool hotelBreakfastInfoPopPool =
            new XxlJobThreadPool(XxlJobNameConstant.SYNC_GREENTREE_BREAKFAST_INFO_POP);

    private static final XxlJobThreadPool hotelRatesPopPool =
            new XxlJobThreadPool(XxlJobNameConstant.SYNC_GREENTREE_RATES_POP);

    private static final XxlJobThreadPool hotelActivityRatesPopPool =
            new XxlJobThreadPool(XxlJobNameConstant.SYNC_GREENTREE_ACTIVITY_RATES_POP);

    @Override
    public void syncGreenTreeHotelIdListTask(String chainCode, String hotelId) {
        GetHotelInfoReq getHotelInfoReq = GetHotelInfoReq.builder()
                .reqHotels(GetHotelInfoReq.ReqHotels.builder()
                        .reqHotel(GetHotelInfoReq.ReqHotels.ReqHotel.builder()
                                .hotelCode(hotelId)
                                .build())
                        .build())
                .build();
        getHotelInfoReq.setChainCode(chainCode);

        GetHotelInfoResp.ReqHotels.ReqHotelBean.HotelBaseInfoBean hotelInfo = null;
        try {
            hotelInfo = greenTreeService.getHotelInfo(getHotelInfoReq)
                    .getReqHotels()
                    .getReqHotel()
                    .getHotelBaseInfo();
        } catch (Exception e) {
            // 请求失败时，酒店可售可预定刷0
            hotelOffLine(hotelId);
            return;
        }
        HtHotelStdInfo htHotelStdInfo = parseHotelInfoData(hotelInfo);
        if (null == htHotelStdInfo) {
            return;
        }
        // 酒店基本信息落库
        htHotelStdInfoService.saveOrUpdate(htHotelStdInfo,
                new LambdaQueryWrapper<HtHotelStdInfo>().eq(HtHotelStdInfo::getHotelId, htHotelStdInfo.getHotelId()));

        //查询房型
        GetRoomTypeListReq getRoomTypeListReq = GetRoomTypeListReq.builder()
                .reqHotels(GetRoomTypeListReq.ReqHotels.builder()
                        .reqHotel(GetRoomTypeListReq.ReqHotels.ReqHotel.builder()
                                .hotelCode(hotelId)
                                .build())
                        .build())
                .build();
        List<GetRoomTypeListResp.ReqHotels.ReqHotel.ReqTypes.ReqType> roomTypeList = null;
        try {
            roomTypeList = greenTreeService.getRoomTypeList(getRoomTypeListReq)
                    .getReqHotels()
                    .getReqHotel()
                    .getReqTypes()
                    .getReqTypeList();
        } catch (Exception e) {
            // 请求酒店房型数据不存在 ， 酒店可售可预定刷0
            hotelOffLine(hotelId);
            return;
        }
        Optional.ofNullable(roomTypeList).orElse(new ArrayList<>()).forEach(roomType -> {
            // 酒店房型落库
            HtRoomTypeStdInfo htRoomTypeStdInfo = new HtRoomTypeStdInfo();
            htRoomTypeStdInfo.setHotelId(htHotelStdInfo.getHotelId());
            htRoomTypeStdInfo.setRoomTypeCode(roomType.getRoomTypeCode());
            htRoomTypeStdInfo.setRoomArea(roomType.getRoomComments().getRoomArea());
            htRoomTypeStdInfo.setMaxCheckIn(roomType.getRoomComments().getPerson());
            Integer windowType = null;
            if (roomType.getRoomComments().getHasWindows() == roomType.getRoomComments().getTotalRooms()) {
                // 明窗数等于总房间数，就一定有窗
                windowType = 1;
            } else if (roomType.getRoomComments().getNoWindows() == roomType.getRoomComments().getTotalRooms()) {
                // 如果无窗数等于总房间数就是无窗
                windowType = 0;
            } else {
                // 其他情况是部分有窗
                windowType = 2;
            }
            htRoomTypeStdInfo.setWindowType(windowType);

            htRoomTypeStdInfo.setAddBed(Optional.ofNullable(roomType.getRoomComments().getAddBeds()).orElse(0) == 0 ? 0 : 1);
//            htRoomTypeStdInfo.setRoomTypeName(getRoomTypeName(roomType.getRoomTypeDescript()));
            // 房型名称描述去除逗号
            htRoomTypeStdInfo.setRoomTypeName(roomType.getRoomTypeDescript().replaceAll(",", ""));
            htRoomTypeStdInfo.setBedType(findBedType(roomType.getRoomTypeDescript()));
            htRoomTypeStdInfo.setBedWidth(roomType.getRoomComments().getBedType());
            htRoomTypeStdInfo.setExtra(JsonUtil.toString(roomType));
            htRoomTypeStdInfoService.saveOrUpdate(htRoomTypeStdInfo,
                    new LambdaQueryWrapper<HtRoomTypeStdInfo>().eq(HtRoomTypeStdInfo::getHotelId,
                                    htRoomTypeStdInfo.getHotelId())
                            .eq(HtRoomTypeStdInfo::getRoomTypeCode, htRoomTypeStdInfo.getRoomTypeCode()));
        });
    }

    private void hotelOffLine(String hotelId) {
        htHotelStdInfoDao.update(null, new LambdaUpdateWrapper<HtHotelStdInfo>()
                .eq(HtHotelStdInfo::getHotelId, greenTreeService.parseInnId(hotelId))
                .set(HtHotelStdInfo::getSourceStatus, 0)
                .set(HtHotelStdInfo::getBookStatus, 0));
    }

    private Integer findBedType(String roomTypeDescript) {
        if (roomTypeDescript.indexOf("大床") != -1) {
            return 0;
        }
        if (roomTypeDescript.indexOf("单人床") != -1) {
            return 1;
        }
        if (roomTypeDescript.indexOf("双床") != -1) {
            return 2;
        }
        if (roomTypeDescript.indexOf("特大床") != -1) {
            return 3;
        }
        if (roomTypeDescript.indexOf("双人床") != -1) {
            return 4;
        }
        return 5;
    }


    /**
     * 获得所有酒店id，并放入redis中
     *
     * @param chainCode
     */
    @Override
    public void syncGreenTreeHotelIdListTaskFastPush(String chainCode) {
        if (redisUtil.setENx(RedisKeyConstant.HOTEL_MAIN_GREENTREE_HOTELID_PUSH, PUSH_EXPIRY,
                RedisKeyConstant.HOTEL_MAIN_GREENTREE_HOTELID_PUSH)) {
            GetAllHotelInfoReq req = new GetAllHotelInfoReq();
            req.setChainCode(chainCode);
            List<GetAllHotelInfoResp.HotelInfoBean> hotelInfos = greenTreeService.getAllHotelInfo(req).getHotelInfos();
            redisUtil.leftPushAll(RedisKeyConstant.HOTEL_MAIN_GREENTREE_HOTELID_LIST,
                    hotelInfos.stream().map(e -> e.getHotelCode()).collect(Collectors.toList()));
        }
    }

    @Override
    public void syncGreenTreeHotelIdListTaskFastPop(String chainCode) {
        hotelInfoPopPool.execute(() -> new SyncGreenTreeHotelIdTaskThread(chainCode));
    }

    @Override
    public void syncGreenTreeBreakfastInfoTaskPush() {
        if (redisUtil.setENx(RedisKeyConstant.HOTEL_MAIN_GREENTREE_BREAKFAST_HOTELID_PUSH, PUSH_EXPIRY,
                RedisKeyConstant.HOTEL_MAIN_GREENTREE_BREAKFAST_HOTELID_PUSH)) {
            deleteExpiredBreakfastInfo();
            List<HtHotelStdInfo> htHotelStdInfos = htHotelStdInfoDao.selectList(
                    new LambdaQueryWrapper<HtHotelStdInfo>()
                            .eq(HtHotelStdInfo::getSourceCode, SourceEnum.GREENTREE.getCode()));
            if (CollectionUtils.isNotEmpty(htHotelStdInfos) && redisUtil.lGetListSize(RedisKeyConstant.HOTEL_MAIN_GREENTREE_BREAKFAST_HOTELID_LIST) <= 0) {
                redisUtil.leftPushAll(RedisKeyConstant.HOTEL_MAIN_GREENTREE_BREAKFAST_HOTELID_LIST,
                        htHotelStdInfos.stream().map(e -> e.getHotelId()).collect(Collectors.toList()));
            }
        }
    }

    /**
     * 删除过期早餐数据,1天前
     */
    private void deleteExpiredBreakfastInfo() {
        LambdaQueryWrapper<HtBreakfastCountGreentree> breakfastCountLambdaQueryWrapper = new LambdaQueryWrapper<>();
        breakfastCountLambdaQueryWrapper.le(HtBreakfastCountGreentree::getCalDate, DateUtils.addDays(new Date(), -1));
        htBreakfastCountGreentreeService.getBaseMapper().delete(breakfastCountLambdaQueryWrapper);
    }

    @Override
    public void syncGreenTreeBreakfastInfoTaskPop(String chainCode, Integer days) {
        hotelBreakfastInfoPopPool.execute(() -> new SyncGreenTreeBreakfastInfoTaskThread(chainCode, days));
    }

    /**
     * 酒店早餐信息落库
     *
     * @param chainCode
     * @param hotelId
     */
    @Override
    public void syncGreenTreeBreakfastInfoTask(String chainCode, String hotelId, String start, String end) {
        // 拉取30天的早餐信息
        GetBreakfastInfoReq getBreakfastInfoReq = GetBreakfastInfoReq.builder()
                .hotelCode(hotelId)
                .startDate(start)
                .endDate(end)
                .build();
        getBreakfastInfoReq.setChainCode(chainCode);
        GetBreakfastInfoResp breakfastInfo = greenTreeService.getBreakfastInfo(getBreakfastInfoReq);

        breakfastInfo.getReqDates().forEach(reqDate -> {
            // 当前天
            String curTime = reqDate.getData();
            reqDate.getReqRooms().forEach(reqRoom -> {
                // 早餐信息入库
                Integer breakfastState = reqRoom.getBreakfastState();
                String roomTypeCode = reqRoom.getRoomTypeCode();
                HtBreakfastCountGreentree htBreakfastCountGreentree = new HtBreakfastCountGreentree();
                try {
                    htBreakfastCountGreentree.setCalDate(new SimpleDateFormat("yyyy-MM-dd").parse(curTime));
                } catch (ParseException e) {
                    throw new RuntimeException(e);
                }
                htBreakfastCountGreentree.setHotelId(greenTreeService.parseInnId(hotelId));
                htBreakfastCountGreentree.setBreakfastCount(breakfastState);
                htBreakfastCountGreentree.setRoomTypeCode(roomTypeCode);
                htBreakfastCountGreentreeService.saveOrUpdate(htBreakfastCountGreentree,
                        new LambdaQueryWrapper<HtBreakfastCountGreentree>()
                                .eq(HtBreakfastCountGreentree::getHotelId, htBreakfastCountGreentree.getHotelId())
                                .eq(HtBreakfastCountGreentree::getCalDate, htBreakfastCountGreentree.getCalDate())
                                .eq(HtBreakfastCountGreentree::getRoomTypeCode, htBreakfastCountGreentree.getRoomTypeCode()));
            });
        });
    }

    @Override
    public void syncGreenTreeRatesTaskPush() {
        if (redisUtil.setENx(RedisKeyConstant.HOTEL_MAIN_GREENTREE_RATES_PUSH, PUSH_EXPIRY,
                RedisKeyConstant.HOTEL_MAIN_GREENTREE_RATES_PUSH)) {
            List<HtHotelStdInfo> htHotelStdInfos = htHotelStdInfoDao.selectList(
                    new LambdaQueryWrapper<HtHotelStdInfo>()
                            .eq(HtHotelStdInfo::getSourceCode, SourceEnum.GREENTREE.getCode())
                            .eq(HtHotelStdInfo::getSourceStatus, 1)
                            .eq(HtHotelStdInfo::getBookStatus, 1));
            if (CollectionUtils.isNotEmpty(htHotelStdInfos)
                    && redisUtil.lGetListSize(RedisKeyConstant.HOTEL_MAIN_GREENTREE_RATES_LIST) <= 0) {
                redisUtil.leftPushAll(RedisKeyConstant.HOTEL_MAIN_GREENTREE_RATES_LIST,
                        htHotelStdInfos.stream().map(HtHotelStdInfo::getHotelId).collect(Collectors.toList()));
            }
        }
    }

    @Override
    public void syncGreenTreeRatesTaskPop(String chainCode, Integer days, String level, String sourceId) {
        hotelRatesPopPool.execute(
                () -> new SyncGreenTreeRatesTaskThread(chainCode, days, level, sourceId)
        );
    }

    @Override
    public void syncGreenTreeRatesTask(String chainCode, String hotelId, String start, String end, String level, String sourceId) {
        // 更新前，刷空库存
        closeRoomQuoto(hotelId, sourceId);

        GetAgreementPriceReq getAllRoomCountAndPrice = GetAgreementPriceReq.builder()
                .hotelCode(hotelId)
                .startDate(start)
                .endDate(end)
                .level(level)
                .build();
        getAllRoomCountAndPrice.setChainCode(chainCode);
        GetAgreementPriceResp allRoomCountAndPrice = greenTreeService.getAgreementPrice(getAllRoomCountAndPrice);

        GetAgreementPriceResp.ReqRooms reqRooms = allRoomCountAndPrice.getReqRooms();
        if (null == reqRooms) {
            return;
        }

        Optional.ofNullable(reqRooms.getReqDateList()).orElse(new ArrayList<>())
                .forEach(reqDate -> {
                    Optional.ofNullable(reqDate.getReqRoomList()).orElse(new ArrayList<>())
                            .forEach(roomStatus -> {
                                // 市场价
                                GetAgreementPriceResp.ReqRooms.ReqDate.ReqRoom.MktPrice mktPrice = Optional.ofNullable(roomStatus.getMktPrice()).orElse(new GetAgreementPriceResp.ReqRooms.ReqDate.ReqRoom.MktPrice());
                                // 采购价
                                GetAgreementPriceResp.ReqRooms.ReqDate.ReqRoom.AgreementRate roomRate = Optional.ofNullable(roomStatus.getAgreementRate()).orElse(new GetAgreementPriceResp.ReqRooms.ReqDate.ReqRoom.AgreementRate());

                                HtPriceCalendarGreentree htPriceCalendarGreentree = new HtPriceCalendarGreentree();
                                htPriceCalendarGreentree.setHotelId(greenTreeService.parseInnId(hotelId));
                                htPriceCalendarGreentree.setRoomTypeName(roomStatus.getRoomTypeDescript().replaceAll(",", ""));
                                htPriceCalendarGreentree.setRoomTypeCode(roomStatus.getRoomTypeCode());
                                Date calDate = null;
                                Calendar cancleDate = Calendar.getInstance();
                                try {
                                    calDate = new SimpleDateFormat("yyyy/MM/dd").parse(reqDate.getDate());
                                    cancleDate.setTime(calDate);
                                    cancleDate.set(Calendar.HOUR_OF_DAY, 18);
                                    cancleDate.set(Calendar.MINUTE, 0);
                                    cancleDate.set(Calendar.SECOND, 0);
                                    cancleDate.set(Calendar.MILLISECOND, 0);
                                } catch (Exception e) {
                                    log.error(e.getMessage(), e);
                                }
                                htPriceCalendarGreentree.setSourceId(sourceId);
                                htPriceCalendarGreentree.setCalDate(calDate);
                                htPriceCalendarGreentree.setBreakfastCount(selectBreakfastCount(greenTreeService.parseInnId(hotelId),
                                        calDate, roomStatus.getRoomTypeCode()));
                                htPriceCalendarGreentree.setQuota(roomStatus.getRoomCount());
                                htPriceCalendarGreentree.setCurrencyCode(roomRate.getCurrencyCode());
                                htPriceCalendarGreentree.setRetailPrice(mktPrice.getPrice());
                                htPriceCalendarGreentree.setPurchasePrice(roomRate.getPrice());
                                /**
                                 * todo 取消规则：订单状态为预定状态且在入住当日18点之前可免费取消，当日订单且在18点之后下单的需要在15分钟内取消
                                 */
                                htPriceCalendarGreentree.setCancelPolicyType(4);
                                htPriceCalendarGreentree.setLastCancelTime(cancleDate.getTime());
//                                htPriceCalendar.setCancelRule();

                                htGreentreePriceCalendarService.saveOrUpdate(htPriceCalendarGreentree,
                                        new LambdaQueryWrapper<HtPriceCalendarGreentree>()
                                                .eq(HtPriceCalendarGreentree::getSourceId, htPriceCalendarGreentree.getSourceId())
                                                .eq(HtPriceCalendarGreentree::getHotelId, htPriceCalendarGreentree.getHotelId())
                                                .eq(HtPriceCalendarGreentree::getRoomTypeCode, htPriceCalendarGreentree.getRoomTypeCode())
                                                .eq(HtPriceCalendarGreentree::getCalDate, htPriceCalendarGreentree.getCalDate()));
                            });
                });
        incrHotelRocketMqProducer.send(greenTreeService.parseInnId(hotelId));
    }

    /**
     * 酒店库存刷 0
     *
     * @param hotelId
     * @param sourceId
     */
    private void closeRoomQuoto(String hotelId, String sourceId) {
        htGreentreePriceCalendarService.update(new LambdaUpdateWrapper<HtPriceCalendarGreentree>()
                .eq(HtPriceCalendarGreentree::getSourceId, sourceId)
                .eq(HtPriceCalendarGreentree::getHotelId, greenTreeService.parseInnId(hotelId))
                .set(HtPriceCalendarGreentree::getQuota, 0));
    }

    @Override
    public void syncGreenTreePicPush() {
        if (redisUtil.setENx(RedisKeyConstant.HOTEL_MAIN_GREENTREE_PIC_PUSH, PUSH_EXPIRY,
                RedisKeyConstant.HOTEL_MAIN_GREENTREE_PIC_PUSH)) {
            List<String> hotelIds = htHotelStdInfoDao.selectList(new LambdaQueryWrapper<HtHotelStdInfo>()
                            .eq(HtHotelStdInfo::getSourceCode, SourceEnum.GREENTREE.getCode())
                            .eq(HtHotelStdInfo::getSourceStatus, 1)
                            .eq(HtHotelStdInfo::getBookStatus, 1))
                    .stream().map(HtHotelStdInfo::getHotelId)
                    .collect(Collectors.toList());
            if (CollectionUtils.isNotEmpty(hotelIds)
                    && redisUtil.lGetListSize(RedisKeyConstant.HOTEL_MAIN_GREENTREE_PIC_LIST) <= 0) {
                redisUtil.leftPushAll(RedisKeyConstant.HOTEL_MAIN_GREENTREE_PIC_LIST, new ArrayList<>(hotelIds));
            }
        }
    }

    @Override
    public void syncGreenTreePicPop() {
        hotelInfoPopPool.execute(SyncGreenTreePicTaskThread::new);
    }

    @Override
    public void syncGreenTreePic(String hotelId) {
        GetHotelInfoReq getHotelInfoReq = GetHotelInfoReq.builder()
                .reqHotels(GetHotelInfoReq.ReqHotels.builder()
                        .reqHotel(GetHotelInfoReq.ReqHotels.ReqHotel.builder()
                                .hotelCode(greenTreeService.parseHotelId(hotelId))
                                .build())
                        .build())
                .build();
        GetHotelInfoResp hotelInfo = greenTreeService.getHotelInfo(getHotelInfoReq);
        String imgUrl = hotelInfo.getReqHotels().getReqHotel().getHotelPictureInfo().getHotelPic().getSmallPic().getImgUrl();
        List<HtHotelStdImage> hotelStdImages = htHotelStdImageService.list(new LambdaQueryWrapper<HtHotelStdImage>()
                .eq(HtHotelStdImage::getHotelId, hotelId)
                .eq(HtHotelStdImage::getImageType, 2));
        if (CollectionUtils.isEmpty(hotelStdImages)) {
            savePicInfo(hotelId, "", 1, imgUrl, "");
            savePicInfo(hotelId, "", 2, imgUrl, "");
        }
    }

    @Override
    public void syncGreenTreeActivityRatesTaskPush() {
        if (redisUtil.setENx(RedisKeyConstant.HOTEL_MAIN_GREENTREE_ACTIVITY_RATES_PUSH, PUSH_EXPIRY,
                RedisKeyConstant.HOTEL_MAIN_GREENTREE_ACTIVITY_RATES_PUSH)) {
            List<HtHotelStdInfo> htHotelStdInfos = htHotelStdInfoDao.selectList(
                    new LambdaQueryWrapper<HtHotelStdInfo>()
                            .eq(HtHotelStdInfo::getSourceCode, SourceEnum.GREENTREE.getCode())
                            .eq(HtHotelStdInfo::getSourceStatus, 1)
                            .eq(HtHotelStdInfo::getBookStatus, 1));
            if (CollectionUtils.isNotEmpty(htHotelStdInfos)
                    && redisUtil.lGetListSize(RedisKeyConstant.HOTEL_MAIN_GREENTREE_ACTIVITY_RATES_LIST) <= 0) {
                redisUtil.leftPushAll(RedisKeyConstant.HOTEL_MAIN_GREENTREE_ACTIVITY_RATES_LIST,
                        htHotelStdInfos.stream().map(HtHotelStdInfo::getHotelId).collect(Collectors.toList()));
            }
        }

    }

    @Override
    public void syncGreenTreeActivityRatesTaskPop(String chainCode, Integer days, String sourceId) {
        hotelActivityRatesPopPool.execute(() -> new SyncGreenTreeActivityRatesTaskThread(chainCode, days, sourceId));
    }

    @Override
    public void syncGreenTreeActivityRatesTask(String chainCode, String hotelId, String start, String end, String sourceId) {
        // 更新前，刷空活动库存
        closeRoomQuoto(hotelId, sourceId);
//        log.info("开始推送酒店 : " + hotelId);
        /**
         *  获取活动房列表 , 得到每个房型的价格码
         *  存在一个房型多个活动价码
         */
        GetActivityRoomListReq getActivityRoomListReq = GetActivityRoomListReq.builder()
                .reqHotels(GetActivityRoomListReq.ReqHotels.builder()
                        .reqHotel(GetActivityRoomListReq.ReqHotels.ReqHotel.builder()
                                .hotelCode(hotelId)
                                .build())
                        .build())
                .build();
        getActivityRoomListReq.setChainCode(chainCode);
        // 过筛无签约酒店
        GetActivityRoomListResp activityRoomList = null;
        try {
            activityRoomList = greenTreeService.getActivityRoomList(getActivityRoomListReq);
        } catch (Exception e) {
            if (e.getMessage().contains("请求的XML参数酒店没有与中介签约")) {
                htHotelStdInfoDao.update(null, new LambdaUpdateWrapper<HtHotelStdInfo>()
                        .eq(HtHotelStdInfo::getHotelId, greenTreeService.parseInnId(hotelId))
                        .set(HtHotelStdInfo::getSourceStatus, 0)
                        .set(HtHotelStdInfo::getBookStatus, 0));
            }
            return;
        }
        if (activityRoomList.getReqHotels() == null) {
            return;
        }
        // 根据房型编号分组 ， <房型编号 : 活动码组>
        Map<String, List<String>> roomActivity = activityRoomList.getReqHotels().getReqHotel().getReqTypes().getReqTypeList().stream()
                .collect(Collectors.groupingBy(GetActivityRoomListResp.ReqHotels.ReqHotel.ReqTypes.ReqType::getRoomTypeCode,
                        Collectors.mapping(GetActivityRoomListResp.ReqHotels.ReqHotel.ReqTypes.ReqType::getActivityCode, Collectors.toList())));

        // 遍历房型
        roomActivity.forEach((roomTypeCode, activityCodeList) -> {
            // 得到最低价的活动价码
            String activityCode = getOneActivityCode(roomTypeCode, activityCodeList, hotelId);
            if (StringUtils.isBlank(activityCode)) {
                return;
            }
            // 查询房态
            GetAllRoomCountAndPriceActivityReq priceActivityReq =
                    GetAllRoomCountAndPriceActivityReq.builder()
                            .hotelCode(hotelId)
                            .startDate(start)
                            .endDate(end)
                            .reqRooms(GetAllRoomCountAndPriceActivityReq.ReqRooms.builder()
                                    .reqRoom(GetAllRoomCountAndPriceActivityReq.ReqRooms.ReqRoom.builder()
                                            .activityCode(activityCode)
                                            .roomTypeCode(roomTypeCode)
                                            .build())
                                    .build())
                            .build();
            GetAllRoomCountAndPriceActivityResp allRoomCountAndPriceActivity = greenTreeService.getAllRoomCountAndPriceActivity(priceActivityReq);

            if (allRoomCountAndPriceActivity.getReqRooms() == null) {
                return;
            }

            // 正价请求
            Map<String, List<GetAllRoomCountAndPriceResp.ReqRooms.ReqDate.ReqRoom>> gtRetailPrice = getAllRoomCountAndPriceResp(hotelId, start, end);

            // 插入价格日历表
            Optional.ofNullable(allRoomCountAndPriceActivity.getReqRooms().getReqDateList())
                    .orElse(new ArrayList<>())
                    .forEach(f -> {
                        // 房态
                        GetAllRoomCountAndPriceActivityResp.ReqRooms.ReqDate.ReqRoom roomStatus = f.getReqRoomList();
                        // 获取门市价
                        BigDecimal retailPrice = null;
                        try{
                            retailPrice = getRetailPrice(gtRetailPrice, roomStatus.getRoomTypeCode(), f.getDate());
                        }catch (Exception e){
                            log.error("获取门市价失败");
                        }
                        HtPriceCalendarGreentree htPriceCalendarGreentree = new HtPriceCalendarGreentree();
                        htPriceCalendarGreentree.setHotelId(greenTreeService.parseInnId(hotelId));
                        htPriceCalendarGreentree.setRoomTypeName(roomStatus.getRoomTypeDescript().replaceAll(",", ""));
                        htPriceCalendarGreentree.setRoomTypeCode(roomStatus.getRoomTypeCode());
                        Date calDate = null;
                        Calendar cancleDate = Calendar.getInstance();
                        try {
                            calDate = new SimpleDateFormat("yyyy-MM-dd").parse(f.getDate());
                            cancleDate.setTime(calDate);
                            cancleDate.set(Calendar.HOUR_OF_DAY, 18);
                            cancleDate.set(Calendar.MINUTE, 0);
                            cancleDate.set(Calendar.SECOND, 0);
                            cancleDate.set(Calendar.MILLISECOND, 0);
                        } catch (Exception ex) {
                            log.error(ex.getMessage(), ex);
                        }
                        htPriceCalendarGreentree.setSourceId(sourceId);
                        htPriceCalendarGreentree.setRateplanId(roomStatus.getActivityCode());
                        htPriceCalendarGreentree.setCalDate(calDate);
                        htPriceCalendarGreentree.setBreakfastCount(selectBreakfastCount(greenTreeService.parseInnId(hotelId),
                                calDate, roomStatus.getRoomTypeCode()));
                        htPriceCalendarGreentree.setQuota(roomStatus.getRoomCount());
                        htPriceCalendarGreentree.setCurrencyCode(roomStatus.getRoomRate().getCurrencyCode());
                        htPriceCalendarGreentree.setRetailPrice(retailPrice);
                        htPriceCalendarGreentree.setPurchasePrice(roomStatus.getRoomRate().getPrice());
                        /**
                         * todo 取消规则：订单状态为预定状态且在入住当日18点之前可免费取消，当日订单且在18点之后下单的需要在15分钟内取消
                         */
                        htPriceCalendarGreentree.setCancelPolicyType(4);
                        htPriceCalendarGreentree.setLastCancelTime(cancleDate.getTime());
//                                htPriceCalendar.setCancelRule();

                        htGreentreePriceCalendarService.saveOrUpdate(htPriceCalendarGreentree,
                                new LambdaQueryWrapper<HtPriceCalendarGreentree>()
                                        .eq(HtPriceCalendarGreentree::getSourceId, htPriceCalendarGreentree.getSourceId())
                                        .eq(HtPriceCalendarGreentree::getHotelId, htPriceCalendarGreentree.getHotelId())
                                        .eq(HtPriceCalendarGreentree::getRoomTypeCode, htPriceCalendarGreentree.getRoomTypeCode())
                                        .eq(HtPriceCalendarGreentree::getCalDate, htPriceCalendarGreentree.getCalDate()));
                    });
        });
    }

    /**
     * 查询一天的活动价，找到最低的活动价码
     */
    private String getOneActivityCode(String roomTypeCode, List<String> activityCodeList, String hotelId) {
        String start = DateUtil.formatDate(new Date(), "yyyy-MM-dd");
        String end = DateUtil.formatDate(DateUtil.addDays(new Date(), 1), "yyyy-MM-dd");
        AtomicReference<String> resCode = new AtomicReference<>("");
        AtomicReference<BigDecimal> resultPrice = new AtomicReference<>(new BigDecimal("10000"));
        activityCodeList.forEach(activityCode -> {
            // 查询房态
            GetAllRoomCountAndPriceActivityReq priceActivityReq =
                    GetAllRoomCountAndPriceActivityReq.builder()
                            .hotelCode(hotelId)
                            .startDate(start)
                            .endDate(end)
                            .reqRooms(GetAllRoomCountAndPriceActivityReq.ReqRooms.builder()
                                    .reqRoom(GetAllRoomCountAndPriceActivityReq.ReqRooms.ReqRoom.builder()
                                            .activityCode(activityCode)
                                            .roomTypeCode(roomTypeCode)
                                            .build())
                                    .build())
                            .build();
            try {
                GetAllRoomCountAndPriceActivityResp allRoomCountAndPriceActivity = greenTreeService.getAllRoomCountAndPriceActivity(priceActivityReq);
                BigDecimal price = allRoomCountAndPriceActivity.getReqRooms().getReqDateList().get(0).getReqRoomList().getRoomRate().getPrice();
                if (price.compareTo(resultPrice.get()) < 0) {
                    resultPrice.set(price);
                    resCode.set(activityCode);
                }
            } catch (Exception e) {
                log.error("获取门市价异常: " + hotelId + " " + roomTypeCode + " " + activityCode + "\n" + e);
            }
        });
        return resCode.get();
    }

    // 获取门市价
    private BigDecimal getRetailPrice(Map<String, List<GetAllRoomCountAndPriceResp.ReqRooms.ReqDate.ReqRoom>> gtRetailPrice, String roomTypeCode, String calDate) {
        // "2023/12/13" -> "2023-12-13"
        //calDate = calDate.replaceAll("-", "/");
        String[] parts = calDate.split("-");
        calDate = parts[0] + "/" + Integer.parseInt(parts[1]) + "/" + Integer.parseInt(parts[2]);
        return Optional.ofNullable(gtRetailPrice.get(calDate)).orElse(null)
                .stream().filter(e -> e.getRoomTypeCode().equals(roomTypeCode))
                .map(e -> e.getMktPrice().getPrice()).findAny().orElse(null);
    }

    // 获得市场价的内容
    private Map<String, List<GetAllRoomCountAndPriceResp.ReqRooms.ReqDate.ReqRoom>> getAllRoomCountAndPriceResp(String hotelId, String start, String end) {
        GetAllRoomCountAndPriceReq getAllRoomCountAndPriceReq = GetAllRoomCountAndPriceReq.builder()
                .hotelCode(hotelId)
                .startDate(start)
                .endDate(end)
                .build();
        GetAllRoomCountAndPriceResp result = greenTreeService.getAllRoomCountAndPrice(getAllRoomCountAndPriceReq);
        // 日期 : 房态
        return result.getReqRooms().getReqDateList().stream()
                .collect(Collectors.toMap(GetAllRoomCountAndPriceResp.ReqRooms.ReqDate::getDate,
                        GetAllRoomCountAndPriceResp.ReqRooms.ReqDate::getReqRoomList, (v1, v2) -> v1));
    }

    private void savePicInfo(String hotelId, String roomTypeCode, Integer type, String sourceUrl, String imageUrl) {
        HtHotelStdImage image = new HtHotelStdImage();
        image.setHotelId(hotelId);
        image.setRoomTypeCode(roomTypeCode);
        image.setImageType(type);
        image.setSourceUrl(sourceUrl);
        image.setImageUrl(imageUrl);
        htHotelStdImageService.save(image);
    }

    /**
     * 获得对应的早餐数
     */
    private Integer selectBreakfastCount(String hotelId, Date calDate, String roomTypeCode) {
        try {
            return htBreakfastCountGreentreeService.getBaseMapper().selectOne(new LambdaQueryWrapper<HtBreakfastCountGreentree>()
                    .eq(HtBreakfastCountGreentree::getHotelId, hotelId)
                    .eq(HtBreakfastCountGreentree::getCalDate, calDate)
                    .eq(HtBreakfastCountGreentree::getRoomTypeCode, roomTypeCode)).getBreakfastCount();

        } catch (Exception e) {
            return null;
        }
    }

    /**
     * 获取房型名称， （大床房,1.5m床）
     */
    private String getRoomTypeName(String roomTypeName) {
        int index = roomTypeName.indexOf(",");
        if (index == -1) {
            return roomTypeName;
        }
        return roomTypeName.substring(0, index);
    }

    private HtHotelStdInfo parseHotelInfoData(GetHotelInfoResp.ReqHotels.ReqHotelBean.HotelBaseInfoBean hotelInfo) {
        if (null == hotelInfo) {
            return null;
        }
        HtHotelStdInfo hotelInfoData = new HtHotelStdInfo();
        hotelInfoData.setSourceCode(SourceEnum.GREENTREE.getCode());
        hotelInfoData.setHotelId(greenTreeService.parseInnId(hotelInfo.getHotelCode()));
        hotelInfoData.setHotelName(hotelInfo.getHotelName());

        hotelInfoData.setHotelAddress(hotelInfo.getHotelAddress());
        hotelInfoData.setHotelTel(hotelInfo.getHotelPhone());
        hotelInfoData.setProvinceName(hotelInfo.getState());
        hotelInfoData.setCityName(hotelInfo.getCityName().endsWith("市") ?
                hotelInfo.getCityName().substring(0, hotelInfo.getCityName().length() - 1) : hotelInfo.getCityName());
        hotelInfoData.setIntroduction(hotelInfo.getMainIntro());
        //来源状态
        hotelInfoData.setBookStatus(1);
        //是否可售
        hotelInfoData.setBookStatus(1);
        hotelInfoData.setOverseas(0);
        hotelInfoData.setSupportForeignGuest(null);

        hotelInfoData.setLongitude(hotelInfo.getLongitude());
        hotelInfoData.setLatitude(hotelInfo.getLatitude());
        hotelInfoData.setMapPointType(0);
        hotelInfoData.setSupportRestaurant(null);
        hotelInfoData.setExtra(JsonUtil.toString(hotelInfo));
        return hotelInfoData;
    }
}
